package com.qiyang.exception;

import org.springframework.http.HttpStatus;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.view.json.MappingJackson2JsonView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;
import java.io.StringWriter;

/**
 * Created on 2020/12/12.
 *
 * @author qiyang.
 * 描述：ControllerAdvice：对Controller的增强
 * 统一异常处理：支持普通视图请求，以及ajax请求
 */
@ControllerAdvice
public class GeneralExceptionHandler {

    @ExceptionHandler(Exception.class)
    public ModelAndView handleException(Exception ex, HttpServletRequest request,
                                        HttpServletResponse response,
                                        HandlerMethod handlerMethod){
        // 根据用户请求的方法是否是一个返回JSON的处理方法
        RestController annotation1 = handlerMethod.getBean().getClass().getAnnotation(RestController.class);
        ResponseBody annotation2 = handlerMethod.getMethod().getAnnotation(ResponseBody.class);
        // 或者判断请求头信息Content-Type包含application/json 或 早期ajax还有一种值x-required-d
        if(annotation1 != null || annotation2 != null) {
            // 此时便可以认为其为ajax请求
            // response.getWriter().write(""); // 此处可以使用jackson替代更方便
            ModelAndView modelAndView = new ModelAndView(new MappingJackson2JsonView());
            // modelAndView 同时支持视图返回和JSON返回
            modelAndView.addObject("code", HttpStatus.INTERNAL_SERVER_ERROR.value());
            modelAndView.addObject("msg", ex.getMessage());
            return modelAndView;
        } else {
            System.out.println("进入全局异常处理器");
            ModelAndView modelAndView = new ModelAndView();
            modelAndView.setViewName("error");
            modelAndView.addObject("ex", ex);
            StringWriter sw = new StringWriter();
            ex.printStackTrace(new PrintWriter(sw));
            System.out.println("打印错误堆栈信息:\n" + sw.toString());
            return modelAndView;
        }
    }

    /**
     * 优先使用本处理器类异常处理，其次匹配全局，全局更精细的异常处理类优先，总体就近原则
     * @param ex
     * @return
     */
    @ExceptionHandler(MissingServletRequestParameterException.class)
    public ModelAndView missingServletRequestParameterException(Exception ex){
        System.out.println("进入全局MissingServletRequestParameter异常处理器");
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.setViewName("error");
        modelAndView.addObject("ex", ex);
        StringWriter sw = new StringWriter();
        ex.printStackTrace(new PrintWriter(sw));
        System.out.println("打印错误堆栈信息:\n" + sw.toString());
        return modelAndView;
    }

}
